import { Context } from 'koa'
import KoaRouter from 'koa-router'
import { loggerFactory } from '@/util/Log4jsUtil'
import { responseSucData } from '@/util/ResponseResultBuilder'
import { SystemException } from '@/exception/SystemException'
import {
  getOsHomeDir,
  getOsTmpDir,
  getProjectPath,
  mkdirAsync,
  mkTmpDirAsync,
  rmAsync,
} from '@/util/FileUtil'
import { basename, join } from 'path'
import { UserDao, UserInstance } from '@/util/SystemDatabaseInit'
import send from 'koa-send'

const logger = loggerFactory('test')

const testControllerRouter = new KoaRouter({ prefix: '/v1/test' })

/**
 * @swagger
 * definitions:
 *   User:
 *     required:
 *       - email
 *       - name
 *     properties:
 *       id:
 *         type: number
 *       email:
 *         type: string
 *         description: 邮箱
 *       name:
 *         type: string
 *         description: 姓名
 *       age:
 *         type: number
 *         description: 年龄
 *       birthday:
 *         type: string
 *         description: 生日
 *       regDate:
 *         type: string
 *         description: 注册日期
 *       remark:
 *         type: string
 *         description: 备注信息
 */

/**
 * @swagger
 * /user:
 *   post:
 *     description: 新增
 *     tags: [用户管理模块]
 *     produces:
 *       - application/json
 *     parameters:
 *       - name: password
 *         description: 用户密码.
 *         in: formData
 *         required: true
 *         type: string
 *       - name: username
 *         description: 用户名.
 *         in: formData
 *         required: true
 *         type: string
 *     responses:
 *       200:
 *         description: 新增成功
 *         schema:
 *           type: object
 *           $ref: '#/definitions/User'
 *
 */
testControllerRouter.post('/user', async (ctx: Context) => {
  logger.debug(`post-body: ${JSON.stringify(ctx.request.body)}`)
  const user = {
    ...ctx.request.body,
    regDate: new Date(),
    birthday: new Date(ctx.request.body.birthday),
  }
  const resp = await UserDao.create(user)
  responseSucData(ctx, resp.toJSON())
})

/**
 * @swagger
 * /user/detail/:id:
 *   get:
 *     description: 获取详情
 *     tags: [用户管理模块]
 *     produces:
 *       - application/json
 *     parameters:
 *       - name: id
 *         description: 用户id
 *         in: path
 *         required: true
 *         type: number
 *     responses:
 *       200:
 *         schema:
 *           type: object
 *           $ref: '#/definitions/User'
 *
 */
testControllerRouter.get('/user/detail/:id', async (ctx: Context) => {
  const { id } = ctx.params
  logger.debug(`get id: ${id}`)
  const resp = await UserDao.findByPk(id)
  responseSucData(ctx, resp && resp.toJSON())
})

testControllerRouter.get('/user/list', async (ctx: Context) => {
  logger.debug(
    `get list: ${JSON.stringify(ctx.query)}, querystring: ${ctx.querystring}`
  )
  const resp = await UserDao.findAll()
  responseSucData(ctx, resp)
})

testControllerRouter.get('/user/exp', async (ctx: Context) => {
  logger.debug(`get exception`)
  throw new Error('非预期异常')
})

testControllerRouter.get('/user/custom-exp', async (ctx: Context) => {
  logger.debug(`get custom-exp`)
  throw new SystemException('预期自定义异常')
})

testControllerRouter.post('/user/form', async (ctx: Context) => {
  logger.debug(`post-form: ${JSON.stringify(ctx.request.body)}`)
  responseSucData(ctx, '')
})

testControllerRouter.put('/user/:id', async (ctx: Context) => {
  const { id } = ctx.params
  logger.debug(`put id: ${id}, body: ${JSON.stringify(ctx.request.body)}`)
  const user = await UserDao.findByPk(id)
  if (user) {
    user.set({ ...ctx.request.body }).save()
  }
  responseSucData(ctx, '')
})

testControllerRouter.delete('/user/:id', async (ctx: Context) => {
  const { id } = ctx.params
  logger.debug(`delete id: ${id}`)
  const user = await UserDao.findByPk(id)
  user && (await user.destroy())
  responseSucData(ctx, '')
})

testControllerRouter.get('/system-dir-info', async (ctx: Context) => {
  const userCreateTmpDir = await mkTmpDirAsync(getOsTmpDir())
  await rmAsync(userCreateTmpDir)
  logger.debug('创建临时文件夹:', userCreateTmpDir)
  const panDirPath = await mkdirAsync(getOsTmpDir(), 'pan')
  responseSucData(ctx, {
    tmpdir: getOsTmpDir(),
    homedir: getOsHomeDir(),
    projectPath: getProjectPath(),
    /**
     * 当前文件所在的目录
     */
    dirname: __dirname,
    userCreateTmpDir,
    panDirPath: panDirPath,
  })
})

testControllerRouter.post('/upload', async (ctx: Context) => {
  const files = ctx.request.files
  let myFile = files.myFile
  /*
  important: 这里通过判断 myFile 是否为数组的方式，使得即使客户端上传了多个文件，实际也只存储第一个文件
  */
  if (myFile instanceof Array) {
    myFile = myFile[0]
  }
  const newFileName = basename(myFile.filepath)
  responseSucData(ctx, {
    fileUrl: `${ctx.origin}/${newFileName}`,
    newFileName: newFileName,
  })
})

testControllerRouter.get('/download', async (ctx: Context) => {
  // 设置下载的文件名
  const fileName = encodeURIComponent('表格.xlsx')
  ctx.set('Content-disposition', 'attachment; filename=' + fileName)

  /*
   * 文件下载
   * __dirname: 在当前表示 TestController.ts 所在文件夹
   * 所以最终 root 值实际表示 PROJECT_ROOT/upload (项目根目录的upload文件夹)
   */
  const root = join(__dirname, '../../upload')
  // 将项目根目录 upload 文件夹下的 `我的表格.xlsx` 文件下载给客户端
  await send(ctx, '我的表格.xlsx', { root })
})

testControllerRouter.get(
  '/download-mutil-file-as-zip',
  async (ctx: Context) => {
    // 设置下载的文件名
    const fileName = encodeURIComponent('表格.xlsx')
    ctx.set('Content-disposition', 'attachment; filename=' + fileName)

    // 文件下载
    const root = join(__dirname, '../../upload')
    await send(ctx, '我的表格.xlsx', { root })
  }
)

export default testControllerRouter
